React Router Setup
The Iquea frontend uses React Router v7 for client-side navigation, providing a seamless single-page application experience.
Router Configuration
The main routing setup is defined in App.tsx:
import { BrowserRouter , Routes , Route } from 'react-router-dom' ;
import { AuthProvider } from './context/AuthContext' ;
import { CartProvider } from './context/CartContext' ;
import Navbar from './components/Navbar' ;
import Footer from './components/Footer' ;
import Home from './pages/Home' ;
import Login from './pages/Login' ;
import Register from './pages/Register' ;
import ProductList from './pages/ProductList' ;
import ProductDetail from './pages/ProductDetail' ;
import Cart from './pages/Cart' ;
import Habitaciones from './pages/Habitaciones' ;
import Nosotros from './pages/Nosotros' ;
import Contacto from './pages/Contacto' ;
import './App.css' ;
function App () {
return (
< AuthProvider >
< CartProvider >
< BrowserRouter >
< div className = "app-container" >
< Navbar />
< main className = "main-content" >
< Routes >
< Route path = "/" element = {<Home />} />
< Route path = "/login" element = {<Login />} />
< Route path = "/register" element = {<Register />} />
< Route path = "/productos" element = {<ProductList />} />
< Route path = "/productos/:id" element = {<ProductDetail />} />
< Route path = "/carrito" element = {<Cart />} />
< Route path = "/habitaciones" element = {<Habitaciones />} />
< Route path = "/nosotros" element = {<Nosotros />} />
< Route path = "/contacto" element = {<Contacto />} />
</ Routes >
</ main >
< Footer />
</ div >
</ BrowserRouter >
</ CartProvider >
</ AuthProvider >
);
}
export default App ;
Route Structure
The application defines 9 main routes:
Home / - Landing page with featured products
Login /login - User authentication page
Register /register - New user registration
Product List /productos - Browse all products
Product Detail /productos/:id - Individual product view
Cart /carrito - Shopping cart (auth required)
Habitaciones /habitaciones - Room inspiration page
Nosotros /nosotros - About us page
Contacto /contacto - Contact information
Route Details
Public Routes
These routes are accessible to all users:
Path Component Description /HomeLanding page with hero and featured products /loginLoginAuthentication form /registerRegisterUser registration form /productosProductListBrowse products with search and filters /productos/:idProductDetailProduct details with add-to-cart /habitacionesHabitacionesRoom-based product inspiration /nosotrosNosotrosCompany information /contactoContactoContact form and information
Protected Routes
Currently, the cart is the only protected route:
Path Component Auth Required /carritoCartYes (soft)
Soft Protection : The cart route is accessible but the Navbar only shows the cart icon when isAuthenticated is true. There’s no explicit route guard in the current implementation.
Dynamic Routes
Product Detail Route
The product detail route uses a URL parameter:
< Route path = "/productos/:id" element = {<ProductDetail />} />
Accessing Route Parameters
src/pages/ProductDetail.tsx
import { useParams } from 'react-router-dom' ;
import { getProducto } from '../api/productos' ;
function ProductDetail () {
const { id } = useParams <{ id : string }>();
const [ producto , setProducto ] = useState < Producto | null >( null );
useEffect (() => {
if ( id ) {
getProducto ( Number ( id )). then ( setProducto );
}
}, [ id ]);
// Render product details...
}
Search Query Parameters
The product list supports search via query parameters:
src/components/Navbar.tsx
import { useNavigate } from 'react-router-dom' ;
function Navbar () {
const navigate = useNavigate ();
const [ searchQuery , setSearchQuery ] = useState ( '' );
function handleSearch ( e : React . FormEvent ) {
e . preventDefault ();
if ( searchQuery . trim ()) {
// Navigate with query parameter
navigate ( `/productos?q= ${ encodeURIComponent ( searchQuery . trim ()) } ` );
setSearchQuery ( '' );
}
}
// ...
}
Navigation
The application uses two main navigation methods:
Declarative Navigation
Using the Link component for standard navigation:
import { Link } from 'react-router-dom' ;
< Link to = "/productos" className = "navbar__link" >
Productos
</ Link >
< Link to = { `/productos/ ${ producto . producto_id } ` } >
View Product
</ Link >
Programmatic Navigation
Using the useNavigate hook for navigation after actions:
import { useNavigate } from 'react-router-dom' ;
function Navbar () {
const navigate = useNavigate ();
const { logout } = useAuth ();
function handleLogout () {
logout ();
navigate ( '/' ); // Redirect to home after logout
}
}
Layout Structure
The routing hierarchy wraps all routes with context providers and shared layout:
AuthProvider
└── CartProvider
└── BrowserRouter
└── App Container
├── Navbar (persistent)
├── <Routes>
│ └── [Dynamic page content]
└── Footer (persistent)
This ensures:
Persistent UI - Navbar and Footer render on all pages
Context availability - Auth and Cart state available to all routes
Smooth transitions - Only the main content area changes between routes
Route Protection (Future Enhancement)
While the current implementation doesn’t have explicit route guards, here’s how you could add them:
src/components/ProtectedRoute.tsx
import { Navigate } from 'react-router-dom' ;
import { useAuth } from '../context/AuthContext' ;
interface Props {
children : React . ReactNode ;
}
export default function ProtectedRoute ({ children } : Props ) {
const { isAuthenticated } = useAuth ();
if ( ! isAuthenticated ) {
return < Navigate to = "/login" replace />;
}
return <>{ children } </> ;
}
import ProtectedRoute from './components/ProtectedRoute' ;
function App () {
return (
< Routes >
{ /* Public routes */ }
< Route path = "/" element = {<Home />} />
< Route path = "/login" element = {<Login />} />
{ /* Protected routes */ }
< Route
path = "/carrito"
element = {
<ProtectedRoute>
<Cart />
</ProtectedRoute>
}
/>
</ Routes >
);
}
Authentication Flow
The authentication flow uses programmatic navigation:
Login Success → Navigate to home or intended page
Logout → Navigate to home
Unauthorized Access → Navigate to login (if implementing route guards)
import { useNavigate } from 'react-router-dom' ;
import { useAuth } from '../context/AuthContext' ;
import { login } from '../api/auth' ;
function Login () {
const navigate = useNavigate ();
const { setToken } = useAuth ();
async function handleSubmit ( credentials : LoginDTO ) {
try {
const { token } = await login ( credentials );
setToken ( token );
navigate ( '/' ); // Redirect after successful login
} catch ( error ) {
// Handle error
}
}
}
Best Practices
Prefer <Link> over <a> tags to prevent full page reloads: // Good
< Link to = "/productos" > Products </ Link >
// Bad - causes full page reload
< a href = "/productos" > Products </ a >
Always validate and convert URL parameters: const { id } = useParams <{ id : string }>();
const productId = Number ( id );
if ( isNaN ( productId )) {
// Handle invalid ID
return < NotFound />;
}
Always encode query parameters: const encodedQuery = encodeURIComponent ( searchQuery . trim ());
navigate ( `/productos?q= ${ encodedQuery } ` );
Next Steps
State Management Learn how AuthContext and CartContext work
API Integration See how pages fetch data from the backend